package com.hxl.tech.gateway.auth.service;

import com.alibaba.fastjson.JSONObject;
import com.hxl.tech.gateway.auth.context.ContextHolder;
import com.hxl.tech.gateway.auth.dao.ApplicationDao;
import com.hxl.tech.gateway.auth.dto.Page;
import com.hxl.tech.gateway.auth.dto.UserInfo;
import com.hxl.tech.gateway.auth.dto.application.ApplicationFindDTO;
import com.hxl.tech.gateway.auth.dto.application.ApplicationStateUpdateDTO;
import com.hxl.tech.gateway.auth.exception.AuthException;
import com.hxl.tech.gateway.auth.model.Application;
import com.hxl.tech.gateway.common.constant.AppConstant;
import com.hxl.tech.gateway.common.constant.Result;
import com.hxl.tech.gateway.common.util.RedisUtil;
import lombok.RequiredArgsConstructor;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import javax.persistence.EntityManager;
import javax.transaction.Transactional;
import java.time.LocalDateTime;
import java.util.List;
import java.util.Objects;
import java.util.UUID;
import java.util.concurrent.TimeUnit;

/**
 * 应用 Service 
 * @author soliddq
 * @date 2023-09-20
 */
@Service
@RequiredArgsConstructor
@Transactional
public class ApplicationService {

    private final ApplicationDao applicationDao;
    private final EntityManager entityManager;

    public Page<Application> page(ApplicationFindDTO findDTO) {

        List<Application> list = applicationDao.find(findDTO, true);
        Long total = applicationDao.count(findDTO);
        return Page.of(findDTO, total, list);
    }

    public List<Application> findAll() {

        return applicationDao.findAll();
    }

    public Application readForOAuth(String appId) {

        return applicationDao.read(appId);
    }

    public Application read(String appId) {

        UserInfo userInfo = ContextHolder.getUserInfo();
        Application application = applicationDao.read(appId);
        if (userInfo.getIsAdmin()) {
            return application;
        }
        if (Objects.nonNull(application) && !application.getUserId().equals(userInfo.getUserId())) {
            return null;
        }
        return application;
    }

    public  Application save(Application application) {

        UserInfo userInfo = ContextHolder.getUserInfo();
        this.checkApplication(userInfo.getUserId(), application.getAppId(), application.getAppName());

        application.setAppId(UUID.randomUUID().toString().replace("-", ""));
        application.setAppSecret(UUID.randomUUID().toString().replace("-", ""));
        application.setState(AppConstant.StateEnum.INIT);
        application.setAppType(AppConstant.APP_TYPE_DEV);
        application.setUserId(userInfo.getUserId());
        application.setCreateBy(userInfo.getRealName());
        application.setCreateTime(LocalDateTime.now());
        entityManager.persist(application);

        String appKey = AppConstant.REDIS_APP_PREFIX + application.getAppId();
        RedisUtil.set(appKey, JSONObject.toJSONString(application), 0, TimeUnit.DAYS);
        return application;
    }

    public  Application update(Application application) {

        Application origApplication = this.read(application.getAppId());
        if (Objects.isNull(origApplication)) {
            throw new AuthException(Result.E10007);
        }

        UserInfo userInfo = ContextHolder.getUserInfo();
        this.checkApplication(userInfo.getUserId(), application.getAppId(), application.getAppName());

        if (StringUtils.isNotEmpty(application.getAppName())) {
            origApplication.setAppName(application.getAppName());
        }
        if (StringUtils.isNotEmpty(application.getRedirectUri())) {
            origApplication.setRedirectUri(application.getRedirectUri());
        }
        if (StringUtils.isNotEmpty(application.getReceiveTokenUri())) {
            origApplication.setReceiveTokenUri(application.getReceiveTokenUri());
        }
        if (Objects.nonNull(application.getRemark())) {
            origApplication.setRemark(application.getRemark());
        }
        entityManager.merge(origApplication);

        String appKey = AppConstant.REDIS_APP_PREFIX + origApplication.getAppId();
        RedisUtil.set(appKey, JSONObject.toJSONString(origApplication), 0, TimeUnit.DAYS);
        return origApplication;
    }

    public Application updateState(ApplicationStateUpdateDTO stateUpdateDTO) {

        Application origApplication = this.read(stateUpdateDTO.getAppId());
        if (Objects.isNull(origApplication)) {
            throw new AuthException(Result.E10007);
        }

        origApplication.setState(stateUpdateDTO.getState());
        entityManager.merge(origApplication);

        String appKey = AppConstant.REDIS_APP_PREFIX + origApplication.getAppId();
        RedisUtil.set(appKey, JSONObject.toJSONString(origApplication), 0, TimeUnit.DAYS);
        return origApplication;
    }


    private void checkApplication(String userId, String appId, String appName) {

        List<Application> applications = applicationDao.listByUserIdAndAppName(userId, appName);
        for (Application application : applications) {
            if (!application.getAppId().equals(appId)) {
                throw new AuthException(Result.E20001, "存在相同应用名称");
            }
        }
    }

}
